package aor2.cpu.blockinterface;

import aor2.components.ElementIO;
import aor2.components.Restorable;
import aor2.components.Signal;
import aor2.cpu.blockcontrol.ControlSignalSet;
import aor2.systembus.SystemBus;

public class InterfaceBlock implements ElementIO, Restorable {
	// TODO ova klasa je za komunikaciju sa arbitratorom

	private static InterfaceBlock singleton = null;
	private Mar mar;
	private Mbr mbr;
	private Signal read, write;
	private SystemBus buses = SystemBus.getInstance();
	private boolean clkFstPhase;

	public static InterfaceBlock getInstance() {
		if (null == singleton) {
			singleton = new InterfaceBlock();
		}
		return singleton;

	}

	private InterfaceBlock() {
		ControlSignalSet css = ControlSignalSet.getInstance();
		mar = new Mar(css.get("mxMar"));
		css.get("MARin").addDestinationElementIO(mar);

		mbr = new Mbr();
		css.get("MBRin").addDestinationElementIO(mbr);
		css.get("M1MBRout").addSourceElementIO(mbr);
		css.get("M2MBRout").addSourceElementIO(mbr);

		// FIXME Marija
		read = css.get("read");
		// read.addDestinationElementIO(this);
		// read.addSourceElementIO(this);

		write = css.get("write");
		// write.addDestinationElementIO(this);
		// write.addSourceElementIO(this);

		this.clkFstPhase = true;
	}

	public Mar mar() {
		return mar;
	}

	public Mbr mbr() {
		return mbr;
	}

	@Override
	public void in() {
		if (read.isActive()
				&& SynchronizationBlock.getInstance().ffc.getOut().isActive()
				&& !SynchronizationBlock.getInstance().Dffc.getOut().isActive()) {
			mbr.setState(buses.getDatabusState());
			buses.setRdbus(false);
			buses.done();
		}
		if (write.isActive() && SynchronizationBlock.getInstance().ffc.getOut().isActive()
				&& !SynchronizationBlock.getInstance().Dffc.getOut().isActive()) {
			buses.setWrbus(false);
			buses.done();
		}
	}

	@Override
	public void out() {
		if (SynchronizationBlock.getInstance().getOEread().isActive()) {
			buses.setAddressbus(mar.getState()); // vec bi trebalo da je
													// postavljen rdbus
			buses.start();
		}
		if (SynchronizationBlock.getInstance().getOEwrite().isActive()) {
			buses.setAddressbus(mar.getState());
			buses.setDatabus(mbr.getState());
			buses.start();
		}
	}

	public Mar getMar() {
		return mar;
	}

	public Mbr getMbr() {
		return mbr;
	}

	public void next() {

		if (clkFstPhase) {

			out();
			// in();
		} else {
			// out();
			in();                   
		}
		/*ConditionSignalSet
				.getInstance()
				.get("run")
				.setActive(
						SynchronizationBlock.getInstance().enFFC.isActive()
								|| !(read.isActive() || write.isActive()));*/
		clkFstPhase = !clkFstPhase;
	}

	@Override
	public String toString() {
		return "InterfaceBlock [" + mar + ", " + mbr + "]";
	}

	public void restore(String restorePoint) {
		if (singleton == null)
			singleton = new InterfaceBlock();
		String trim = restorePoint.replace(beginTag(), "");
		trim = trim.replace(endTag(), "");
		trim = trim.trim();
		String[] states = trim.split(" ");
		mar.setState(Long.parseLong(states[0], 16));
		mbr.setState(Long.parseLong(states[1], 16));
		clkFstPhase = Boolean.parseBoolean(states[2]);
		// TODO postaviti clkFstPhase na odgovarajucu vrednost

	}

	public String createRestorePoint() {
		return beginTag() + "\n\t" + Long.toHexString(mar.getState()) + " "
				+ Long.toHexString(mbr.getState()) + " " + clkFstPhase + "\n"
				+ endTag();
	}

	public String beginTag() {
		return "<InterfaceBlock>";
	}

	public String endTag() {
		return "</InterfaceBlock>";
	}

	public void previousClk() {
		mar.previousClk();
		mbr.previousClk();
		clkFstPhase = true;
	}
}
